/*
 * ACM_FEM_SeparateCG_Controller.h
 *
 *      Author: Jerome RD Soine and Christoph A Brand
 *      Institution: Schwarz goup, Institute for Theoretical Physics, Heidelberg University, Germany
 */

#ifndef ACMFA_FEM_SEPARATECG_CONTROLLER_H_
#define ACMFA_FEM_SEPARATECG_CONTROLLER_H_

#include <string>
#include <iostream>
#include "ACM_FEM/OptimizationObject.h"
#include "include/base/cell_models/ACM/ActiveCableModel_FA.h"
#include "ACM_FEM/SeparatedCGOptimizer.h"
#include "ACM_FEM/SeparatedCGOptimizerForACM_FA.h"
#include "include/base/utility/FieldInterpolation2D.h"
#include "include/base/utility/FileHelper.h"
#include "include/core/utility/VectorOperations.h"
#include "ACM_FEM/DataSimulator.h"

using namespace std;

class ACMFA_FEM_SeparateCG_Controller {
public:
	ACMFA_FEM_SeparateCG_Controller(string parameter_file){
		OptimizationObject* opti_object = new OptimizationObject(parameter_file);
		system(("mkdir " + opti_object->get_project_folder()).c_str());
		opti_object->save_parameters(opti_object->get_project_folder() + "/parameter_settings.log");

		if(opti_object->is_simulated_data_enabled()){
			DataSimulator ds(opti_object,true);
			ds.write_displacement_file(opti_object->get_project_folder() + "/sim_disp.txt",10000);
			opti_object->set_disp_file(opti_object->get_project_folder() + "/sim_disp.txt");
		}

		//Init ForceTransmission shapes from file
		vector<Shape*> shapes = Ellipse::get_shapes_from_file(opti_object->get_shape_file());
		vector<Ellipse*> ellipses(shapes.size());
		for(unsigned int i=0; i<shapes.size(); i++) ellipses[i] = (Ellipse *) shapes[i];

		//Save experimental displacements in vtk format for visualization
		Point<2> p1(opti_object->get_mesh_point1()(0),opti_object->get_mesh_point1()(1));
		Point<2> p2(opti_object->get_mesh_point2()(0),opti_object->get_mesh_point2()(1));
		FieldInterpolation2D * interpol = new FieldInterpolation2D(p1, p2, opti_object->get_degree_of_refinement(), opti_object->get_disp_file());
		interpol->output("displacements.vtk");

		interpol->output(opti_object->get_project_folder() + "/displacements.vtk");
		if(opti_object->is_preshifting_enabled())
		{
			//Shift mesh to reference (=nondisplaced) state
			ActiveCableModel::createShiftedVTK(
										opti_object->get_cell_mesh_file(),
										opti_object->get_project_folder() + "/tmp.vtk",
										interpol);
			opti_object->set_cell_mesh_file(opti_object->get_project_folder() + "/tmp.vtk");

			//Shift shapes to corresponding positions
			for(unsigned int i=0; i<ellipses.size(); i++){
				vector<double> tomove = ellipses[i]->get_center();
				Vector<double> tmp (2);
				Point<2> p(tomove[0], tomove[1]);
				interpol->point_evaluation(p, tmp);
				for(int j=0; j<10;j++){
					tomove[0]=tomove[0]-tmp[0];
					tomove[1]=tomove[1]-tmp[1];
					Vector<double> backShift(2);
					Point<2> controlP(tomove[0], tomove[1]);
					interpol->point_evaluation(controlP, backShift);
					controlP[0] += backShift[0];
					controlP[1] += backShift[1];

					Point<2> distance = controlP-p;
					tmp[0] = distance[0];
					tmp[1] = distance[1];
				}
				ellipses[i]->set_center(tomove);
			}

		}

		int dofnr = ActiveCableModel_FA::getFiberList(opti_object->get_cell_mesh_file()).size()+1;
		vector<double> solution (dofnr, 0);
		if(opti_object->is_tension_input_enabled()) solution = FileHelper::get_vector_double_from_file(opti_object->get_tension_file());

		cout << "starting solution: \n";
		VectorOperations::cout_std_vector(solution);
		ActiveCableModel_FA * acm = new ActiveCableModel_FA(opti_object->get_cell_mesh_file(),opti_object->get_project_folder(),50.0,solution, ellipses);
		FEMCalc * fem = new FEMCalc(opti_object->get_young_mod(),opti_object->get_poisson_ratio(),opti_object->get_mesh_point1(),
				opti_object->get_mesh_point2(),opti_object->get_degree_of_refinement(),acm->getForceTransmissionShapes());
		L2Comparator * comp = new L2Comparator(new DataContainer(opti_object->get_disp_file()));
		SeparatedCGOptimizerForACM_FA * opt = new SeparatedCGOptimizerForACM_FA(acm, fem, comp,opti_object->get_project_folder(), opti_object->get_n_optimization_steps(), opti_object->get_n_threads(), 0.001, 0.001, 10, true);
		opt->run();
	};
};


#endif /* ACMFA_FEM_SEPARATECG_CONTROLLER_H_ */
